import { Injectable,CanActivate, ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { JwtService } from "@nestjs/jwt";
import { Request } from "express";
import { UnauthorizedException } from "@nestjs/common/exceptions";
import { IS_PUBLIC_KEY } from "./public.decorator";
import { tokenKey } from "../../utils";
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService, private reflector: Reflector) {}

  /**
 * 确定请求是否可以被激活，基于执行上下文。
 * 
 * 该方法主要检查请求的资源或路由是否被标记为公开；如果是，则直接允许访问。
 * 否则，通过JWT认证验证请求，确保请求是被授权的。
 * 
 * @param context 执行上下文，包含当前请求的信息，例如路由和处理程序。
 * @returns 返回一个Promise<boolean>，true表示请求可以继续，false表示请求不能继续。
 */
async canActivate(context: ExecutionContext): Promise<boolean> {
    // 检查当前请求是否被标记为公开
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) {
      // 如果请求是公开的，直接允许访问
      return true;
    }
    // 从执行上下文中获取HTTP请求对象
    const request = context.switchToHttp().getRequest();
    // 从请求头中提取令牌
    const token = this.extractTokenFromHeader(request);
    // 如果未找到令牌，抛出未授权异常
    if (!token) {
      throw new UnauthorizedException('未登录');
    }
    try {
      // 验证令牌并获取负载
      const payload = await this.jwtService.verifyAsync(token, {
        secret: tokenKey,
      });
      // 将验证后的负载附加到请求对象，以便后续处理
      request['user'] = payload;
    } catch {
      // 如果令牌验证失败，抛出未授权异常
      throw new UnauthorizedException('授权异常');
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}